package zhongbo.javaweb.instagram.web.controller;

import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.model.Filters;
import com.mongodb.client.model.UpdateOptions;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import zhongbo.javaweb.instagram.dto.JsonRespDto;
import zhongbo.javaweb.instagram.enums.InsKey;
import zhongbo.javaweb.instagram.enums.ServiceType;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;

/**
 * 说明：
 *
 * @author zhongboWork
 * @version 1.0
 * @since 2022-01-04 10:30
 */
@Controller
@RequestMapping("Ins/post")
@Api(value = "Ins帖子相关接口", tags = {"Ins帖子相关接口"})
@Slf4j
public class InsPostController {

    @Autowired
    private MongoTemplate mongoTemplate;

    @Value("${userProfileName}")
    private String userProfileName = "userProfile";

    @Value("${userPostName}")
    private String userPostName = "userPost";

    @Value("${service.type}")
    private ServiceType serviceType;

    private MongoCollection<Document> userProfileCollection;
    private MongoCollection<Document> userPostCollection;

    @PostConstruct
    public void init() {
        userPostCollection = mongoTemplate.getCollection(userPostName);
        userProfileCollection = mongoTemplate.getCollection(userProfileName);
    }

    @ResponseBody
    @RequestMapping(method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ApiOperation(value = "添加或更新一条记录接口")
    public JsonRespDto<UpdateResult> addOrUpdateOne(@RequestBody Document entity) {
        Object id = entity.get(InsKey.ID);
        if (StringUtils.isEmpty(id)) {
            return new JsonRespDto<UpdateResult>().makeError().appendMsg("未指定id");
        }
        if (!(id instanceof String)) {
            return new JsonRespDto<UpdateResult>().makeError().appendMsg("id必须为字符串");
        }
        String idTrim = String.valueOf(id).trim();
        if (StringUtils.isEmpty(idTrim)) {
            return new JsonRespDto<UpdateResult>().makeError().appendMsg("id为空");
        }
        Bson bson = Filters.eq(InsKey.ID, id);
        FindIterable<Document> documents = userPostCollection.find(bson);
        Document first = documents.first();
        Document edit = Document.parse(entity.toJson());
        doCompress(edit, first);
        UpdateResult updateResult;
        if (first == null) {
            log.info("addOne id {}", id);
            // @see <a href="https://blog.csdn.net/weixin_39031707/article/details/103622135">Invalid BSON field name xx 问题解决</a>
            Document insert = new Document(InsKey.SET, edit);
            updateResult = userPostCollection.updateOne(bson, insert, new UpdateOptions().upsert(true));
        } else {
            log.info("updateOne id {}", id);
            Document document = new Document(first);
            document.remove("_id");
            // 更新的时候要加"$set"
            // @see <a href="https://blog.csdn.net/weixin_39031707/article/details/103622135">Invalid BSON field name xx 问题解决</a>
            Document insert = new Document(InsKey.SET, first);
            updateResult = userPostCollection.updateOne(bson, insert, new UpdateOptions().upsert(false));
        }
        return new JsonRespDto<UpdateResult>().setData(updateResult).makeSuccess();
    }

    private void doCompress(Document document, Document data) {
        if (serviceType == ServiceType.one && data != null) {
            List<Document> timingSequenceData = data.getList("timingSequenceData", Document.class);
            if (timingSequenceData != null && !timingSequenceData.isEmpty()) {
                // 更新数据
                List<Document> updateData = document.getList("timingSequenceData", Document.class);
                List<Document> newData = new ArrayList<>(timingSequenceData);
                if (updateData != null && !updateData.isEmpty()) {
                    newData.addAll(updateData);
                    log.info("one_更新数据字段 'timingSequenceData'; newVal={}, oldVal={}", newData, timingSequenceData);
                }
                document.put("timingSequenceData", newData);
            }
            List<String> oldData = data.getList("image_paths", String.class);
            if (oldData != null && !oldData.isEmpty()) {
                // 更新数据
                List<String> updateData = document.getList("image_paths", String.class);
                List<String> newData = new ArrayList<>(oldData);
                if (updateData != null && !updateData.isEmpty()) {
                    boolean updated = false;
                    for (String updateDatum : updateData) {
                        if (!newData.contains(updateDatum)) {
                            updated = true;
                            newData.add(updateDatum);
                        }
                    }
                    if (updated) {
                        log.info("one_更新数据字段 'image_paths'; newVal={}, oldVal={}", newData, oldData);
                    }
                }
                document.put("image_paths", newData);
            }
        }
    }

    @ResponseBody
    @RequestMapping(value = "/{id}", method = RequestMethod.DELETE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ApiOperation(value = "删除一条记录接口")
    public JsonRespDto<DeleteResult> delete(@PathVariable(InsKey.ID) String id) {
        if (StringUtils.isEmpty(id)) {
            return new JsonRespDto<DeleteResult>().makeError().appendMsg("未指定id");
        }
        Bson bson = Filters.eq(InsKey.ID, id);
        DeleteResult deleteResult = userPostCollection.deleteOne(bson);
        long deletedCount = deleteResult.getDeletedCount();
        log.info("删除{}条记录,id={}", deletedCount, id);
        return new JsonRespDto<DeleteResult>().setData(deleteResult).makeSuccess();
    }

    @ResponseBody
    @RequestMapping(value = "/delete", method = RequestMethod.DELETE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ApiOperation(value = "删除多个记录接口")
    public JsonRespDto<DeleteResult> deleteList(@RequestBody List<String> ids) {
        if (ids.isEmpty()) {
            return new JsonRespDto<DeleteResult>().makeError().appendMsg("未指定id");
        }
        Bson bson = Filters.in(InsKey.ID, ids);
        DeleteResult deleteResult = userPostCollection.deleteMany(bson);
        long deletedCount = deleteResult.getDeletedCount();
        log.info("删除{}条记录,ids={}", deletedCount, ids);
        return new JsonRespDto<DeleteResult>().setData(deleteResult).makeSuccess();
    }

    @ResponseBody
    @RequestMapping(value = "/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ApiOperation(value = "查询一条记录接口")
    public JsonRespDto<Document> findOneById(@PathVariable(InsKey.ID) String id) {
        if (StringUtils.isEmpty(id)) {
            return new JsonRespDto<Document>().makeError().appendMsg("未指定id");
        }
        Bson bson = Filters.eq(InsKey.ID, id);
        FindIterable<Document> documents = userPostCollection.find(bson).limit(1);
        Document first = documents.first();
        return new JsonRespDto<Document>().setData(first).makeSuccess();
    }

    @ResponseBody
    @RequestMapping(method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ApiOperation(value = "分页条件查询记录接口")
    public JsonRespDto<List<Document>> findPage(@ApiParam(required = true, value = "查询数量(1~100)") int pageSize,
                                                @ApiParam(required = true, value = "查询页数(1~n)") int pageNumber) {
        if (pageSize <= 0) {
            pageSize = 1;
        }
        int maxPageSize = 100;
        if (pageSize > maxPageSize) {
            pageSize = maxPageSize;
        }
        int startOffset = pageNumber > 0 ? (pageNumber - 1) * pageSize : 0;
        FindIterable<Document> limit = userPostCollection.find().limit(pageSize).skip(startOffset);
        MongoCursor<Document> iterator = limit.iterator();
        List<Document> results = new ArrayList<>();
        while (iterator.hasNext()) {
            Document next = iterator.next();
            results.add(next);
        }
        return new JsonRespDto<List<Document>>().setData(results).makeSuccess();
    }

    @ResponseBody
    @RequestMapping(value = "/count", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @ApiOperation(value = "查询记录总数接口")
    public JsonRespDto<Long> count() {
        long count = userPostCollection.estimatedDocumentCount();
        return new JsonRespDto<Long>().setData(count).makeSuccess();
    }

}
